#include "GateService.h"
#include "Server/GateServiceFactory.h"
#include "base/core/os/debug.h"
#include "base/core/Profiler.h"
#include "base/core/random.h"
#include "Common/Utility/ServiceUtility.h"
#include "Common/Utility/ServerTime.h"
#include "Common/Utility/TimeUtility.h"
#include "Common/LoginDefine.h"
#include "Common/NetPack/NetPack.h"
#include "ProtoBuffer/AllProtocol.h"
#include "GateMgr.h"
#include "base/core/log.h"
#include "base/core/os/time.h"
#include "../Server/ServiceMgr.h"
#include "Common/ErrCollect/ErrCollect.h"
#include "Common/ProfileLog/ProfileLog.h"
#include "Common/ComDefine.pb.h"

namespace
{
	static const char s_config_file[] = "./config.lua";
}

Service*  MakeGateService()
{
	return GateService::Instance();
}

void  DeleteGateService(Service* service)
{
	_UNUSE(service);
	GateService::Destroy();
}

GateService::GateService()
	: Service(GATE_SERVER)
	, m_listenPort(0)
	, m_listenHandle(nullptr)
	, m_syncStateTick(0)
	, m_pMessageDispatch(nullptr)
	, m_tmpbuf(nullptr)
	, m_pCenterSession(nullptr)
{
	m_zid = 0;
	memset(m_listenIp, 0, sizeof(m_listenIp));
	m_tmpbuf = new char[MAX_CLIENT_NET_PACK_LENGTH];
	memset(m_tmpbuf, 0, MAX_CLIENT_NET_PACK_LENGTH);
}

GateService::~GateService()
{}

bool GateService::Init(Net* net, const char* configFile)
{
	bool result = false;
	bool retCode = false;

	MMO_ASSERT(net);
	m_net = net;

	m_pMessageDispatch = new MessageDispatch(this);
	MMOLOG_PROCESS_ERROR(m_pMessageDispatch);

	retCode = _LoadConfig(configFile);
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = _ListenAddress();
	MMOLOG_PROCESS_ERROR(retCode);

	retCode = _ListenClientAddress();
	MMOLOG_PROCESS_ERROR(retCode);

	MMOLOG_PROCESS_ERROR(g_MakeGateMgr());
	MMOLOG_PROCESS_ERROR(g_GetGateMgr()->Init());

	snprintf(m_srvTotalName, SERVER_NAME, "zone%d_gate%d", m_zid, m_id);

	LogInfoFmtPrint("%s started ...", m_srvTotalName);
	SetRuningStatus(STATUS_RUNNING);

	m_profileTimeMs = Time::Tick();
	result = true;
Exit0:
	return result;
}

bool GateService::_LoadConfig(const char* config_file) 
{
	bool result = false;
	bool retCode = false;
	LuaParser  parser;

	MMO_ASSERT(config_file);
	if (!parser.OpenFile(config_file)) 
	{
		LogErrFmtPrint("[log] open config file %s fail", config_file);
		goto Exit0;
	}
	{
		LuaRef gate = parser.GetRef("Gate");
		MMOLOG_PROCESS_ERROR(gate.isTable());

		retCode = GetLuaTableValue(gate, "ID", &m_id);
		MMOLOG_PROCESS_ERROR(retCode);

		MMO_ASSERT(m_id > 0);

		retCode = GetLuaTableValue(gate, "ServerIP", m_listenIp, countof(m_listenIp));
		MMOLOG_PROCESS_ERROR(retCode);
		retCode = GetLuaTableValue(gate, "ServerPort", &m_listenPort);
		MMOLOG_PROCESS_ERROR(retCode);

		retCode = GetLuaTableValue(gate, "ClientIP", m_clientListenIp, countof(m_clientListenIp));
		MMOLOG_PROCESS_ERROR(retCode);
		retCode = GetLuaTableValue(gate, "ClientPort", &m_clientPort);
		MMOLOG_PROCESS_ERROR(retCode);

		retCode = GetLuaTableValue(gate, "Zid", &m_zid);
		MMOLOG_PROCESS_ERROR(retCode);

		LuaRef  connect = gate["ConnectServers"];
		MMOLOG_PROCESS_ERROR(connect.isTable());

		retCode = LoadConfigConnect2Service(connect, "Log", &m_logServer);
		MMOLOG_PROCESS_ERROR(retCode);
		m_logServer.connectState = CONNECT_STATE_READY;

		retCode = LoadConfigConnect2Service(connect, "Zone", &m_zoneServer);
		MMOLOG_PROCESS_ERROR(retCode);
		m_zoneServer.connectState = CONNECT_STATE_READY;
	}
	result = true;
Exit0:
	return result;
}

bool GateService::_ListenAddress() 
{
	bool result = false;
	ConnectPeer peer;

	MMOLOG_ASSERT_EXIT(m_net);
	MMOLOG_ASSERT_EXIT(m_listenPort != 0);

	peer.ip = m_listenIp;
	peer.port = m_listenPort;
	peer.req = (void*)GateService::_OnAcceptServer;
	peer.context = this;
	peer.sub_func = SubServerNetPack;
	peer.recvBufSize = INNER_RECVBUF_DEFAULT_SIZE;
	peer.sendBufSize = INNER_SENDBUF_DEFAULT_SIZE;

	m_listenHandle = m_net->Listen(&peer);
	if (m_listenHandle == NULL) 
	{
		LogErrFmtPrint("[log] listen(%s:%d) fail", m_listenIp, m_listenPort);
		goto Exit0;
	}
	LogInfoFmtPrint("[log] listen(%s:%d) success", m_listenIp, m_listenPort);
	result = true;
Exit0:
	return result;
}

bool GateService::_ListenClientAddress() 
{
	bool result = false;
	ConnectPeer peer;

	MMOLOG_ASSERT_EXIT(m_net);
	MMOLOG_ASSERT_EXIT(m_clientPort != 0);

	peer.ip = m_listenIp;
	peer.port = m_clientPort;
	peer.req = (void*)GateService::_OnAcceptClient;
	peer.context = this;
	peer.sub_func = SubClientNetPack;
	peer.recvBufSize = 1024 * 32;
	peer.sendBufSize = 1024 * 50;

	m_clientListenHandle = m_net->Listen(&peer);
	if (m_clientListenHandle == NULL) 
	{
		LogErrFmtPrint("[gate] listen(%s:%d) fail", m_listenIp, m_clientPort);
		goto Exit0;
	}
	LogInfoFmtPrint("[gate] listen(%s:%d) : outerip(%s:%d) success", m_listenIp, m_listenPort, m_listenIp, m_clientPort);
	result = true;
Exit0:
	return result;
}

bool GateService::_OnAcceptServer(ISession* session, void* context) 
{
	PROFILE_SEGMENT("GameRouterService::_OnAcceptServer");

	MMO_ASSERT(session);
	MMO_ASSERT(context);

	GateService* service = (GateService*)context;

	session->SetUserReq((void*)(GateService::_OnCloseServer), context);
	session->SetNetPackHandle((void*)(service->GetServiceMessageDispatch()));

	LogInfoFmtPrint("[gate] server %s connected", session->GetRemoteAddress().IPAndPort);;

	return true;
}

bool GateService::AddLogicSession(uint32_t logicId, ISession *pSession)
{
	bool result = false;
	bool retCode = false;
	SESSION_USER_DATA userData;
	MMO_ASSERT(pSession);
	retCode = m_logicSessionMap.insert(SESSION_MAP::value_type(logicId, pSession)).second;
	MMOLOG_PROCESS_ERROR(retCode);

	userData.v32 = logicId;
	pSession->SetMark(LOGIC_SERVER);
	pSession->SetUserData(userData);

	result = true;
Exit0:
	return result;
}

bool GateService::AddCenterSession(uint32_t centerId, ISession* pSession)
{
	SESSION_USER_DATA userData;
	userData.v32 = centerId;
	m_pCenterSession = pSession;;
	pSession->SetMark(CENTER_SERVER);
	pSession->SetUserData(userData);

	return true;
}

bool GateService::_OnCloseServer(ISession* session, void* context, CloseFlag flag) 
{
	bool result = false;
	GateService*      service = NULL;
	uint32_t          serverID = 0;
	std::string       sessionName = "unknown";
	ServiceType       serviceType = SERVER_TYPE_NULL;
	SESSION_USER_DATA userData;

	MMOLOG_ASSERT_EXIT(session != NULL);
	MMOLOG_ASSERT_EXIT(context != NULL);
	service = (GateService*)context;
	userData = session->GetUserData();
	serverID = userData.v32;
	serviceType = (ServiceType)session->GetMark();

	MMOLOG_PROCESS_ERROR(service != nullptr);
	if (serviceType > SERVER_TYPE_NULL && serviceType < SERVICE_COUNT)
	{
		sessionName = s_service_name[serviceType];
	}
	else if (serviceType > WEB_SERVER_TYPE_NULL && serviceType < WEB_SERVICE_COUNT)
	{
		sessionName = s_web_service_name[serviceType % 100];
	}

	switch (serviceType)
	{
	case CENTER_SERVER:
		service->m_pCenterSession = nullptr;
		break;
	case LOGIC_SERVER:
		service->m_logicSessionMap.erase(serverID);
		break;
	case LOG_SERVER:
		service->m_logServer.session = nullptr;
		service->m_logServer.connectState = CONNECT_STATE_READY;
		break;
	case ZONE_SERVER:
		service->m_zoneServer.session = nullptr;
		service->m_zoneServer.connectState = CONNECT_STATE_READY;
		break;
	default:
		break;
	}

	service->ResetSessionTimeOut(session, MAX_SERVER_TIME_MSEC);
	LogInfoFmtPrint("[gate] %s(id:%u,ip:%s) closed(%d)",
		sessionName.c_str(),
		serverID,
		session->GetRemoteAddress().IPAndPort,
		flag);

	result = true;
Exit0:
	return result;
}

void GateService::UnInit()
{
	if (m_listenHandle != nullptr) 
	{
		m_net->CloseListen(m_listenHandle);
		m_listenHandle = nullptr;
	}

	MMO_DELETE(m_pMessageDispatch);
	MMO_DELETE(m_tmpbuf);
}

bool GateService::Update(uint64_t tick)
{
	bool result = false;

	BEGIN_PROFILE("GateService::_ProcessConnection");
	_ProcessConnection();
	END_PROFILE();

	BEGIN_PROFILE("GateService::_SyncServiceState");
	_SyncServiceState();
	END_PROFILE();

	BEGIN_PROFILE("GateService::SendErrLog");
	if (ServerTime::CheckPerSecs(120)) 
	{
		SendErr(m_logServer.session, EMODULE_ID_SERV_SYS, SERVER_ERR_LOG_COLLECT);
	}
	END_PROFILE();

	if (ServerTime::CheckPerSecs(60)) 
	{
		uint32_t num = m_clientSessionMap.size();
		if (num > 0)
			m_lstOnline.push_back(num);
	}
	if (IsQuitting() && _CheckQuittingComplete()) 
	{
		goto Exit0;
	}

	result = true;
Exit0:
	return result;
}

bool GateService::Quit()
{
	bool result = false;

	MMOLOG_PROCESS_ERROR(IsRuning());
	SetRuningStatus(STATUS_QUITTING);
	result = true;
Exit0:

	//输出现在人数
	LogAlwaysFmtPrint("gateway player count =%d", this->GetPlayerCount());
	return result;
}

bool GateService::_CheckQuittingComplete() 
{
bool result = false;
	MMO_PROCESS_ERROR(IsQuitting());
	result = true;
Exit0:
	return result;
}

bool GateService::HandleConsoleCmd(const char* cmd)
{
	return (cmd[0] != '\0');
}

IMessageDispatch *GateService::GetServiceMessageDispatch()
{
	return m_pMessageDispatch;
}

bool GateService::_ProcessConnection() 
{
	bool result = false;
	bool retCode = false;
	time_t timeInSecond = Time::Now().UnixSec();

	// log
	if (m_logServer.connectState != CONNECT_STATE_CONNECTED)
	{
		retCode = ConnectService(m_net, &m_logServer, timeInSecond, GateService::_OnConnectLogServer, this);
		MMOLOG_PROCESS_ERROR(retCode);
	}

	// gamerouter
	if (m_zoneServer.connectState != CONNECT_STATE_CONNECTED)
	{
		retCode = ConnectService(m_net, &m_zoneServer, timeInSecond, GateService::_OnConnectZoneServer, this);
		MMOLOG_PROCESS_ERROR(retCode);
	}
	result = true;
Exit0:
	return result;
}

bool GateService::_SyncServiceState() 
{
	uint64_t tick = Time::Tick();
    bool result = false;
    bool retCode = false;

	if (tick < m_syncStateTick + SERVER_PING_INTERVAL * 1000)
		return true;

	if (m_logServer.connectState == CONNECT_STATE_CONNECTED)
	{
		retCode = SendData(m_logServer.session, EMODULE_ID_SERV_SYS, LOG_SERVER_PROTOCOL_PING);
		MMOLOG_PROCESS_ERROR(retCode);
	}

	if (m_zoneServer.connectState == CONNECT_STATE_CONNECTED) 
	{
		retCode = SendData(m_zoneServer.session, EMODULE_ID_SERV_SYS, MASTER_SERVER_PROTOCOL_PING);
		MMOLOG_PROCESS_ERROR(retCode);
	}

	m_syncStateTick = tick;
    result = true;
Exit0:
	return result;
}

bool GateService::_OnConnectLogServer(ISession* session, void* context, bool success)
{
	PROFILE_SEGMENT(" GameRouterService::_OnConnectAccountDBServer");

	bool result = false;
	SESSION_USER_DATA userdata;
	GateService* service = NULL;
	ServiceConnect* serviceConnect = NULL;

	MMOLOG_ASSERT_EXIT(context != NULL);
	service = (GateService*)context;
	serviceConnect = &service->m_logServer;

	if (success) 
	{
		MMOLOG_ASSERT_EXIT(session != NULL);
		serviceConnect->session = session;
		serviceConnect->connectState = CONNECT_STATE_CONNECTED;
		serviceConnect->serviceType = LOG_SERVER;
		serviceConnect->session->SetUserReq((void*)(GateService::_OnCloseServer), context);
		serviceConnect->session->SetNetPackHandle((void*)(service->GetServiceMessageDispatch()));
		LogInfoFmtPrint("[gate] connect log server(id:%u, ip:%s:%d) success",
						serviceConnect->id,
						serviceConnect->remoteIp,
						serviceConnect->remotePort);

		userdata.v32 = serviceConnect->id;
		session->SetUserData(userdata);
		session->SetMark(LOG_SERVER);
	}
	else 
	{
		LogErrFmtPrint("[gate] connect log server(id:%u, ip:%s:%d) fail",
						serviceConnect->id,
						serviceConnect->remoteIp,
						serviceConnect->remotePort);
		serviceConnect->connectState = CONNECT_STATE_READY;
	}

	result = true;
Exit0:
	return result;
}

bool GateService::_OnConnectZoneServer(ISession* session, void* context, bool success)
{
	PROFILE_SEGMENT(" GateService::_OnConnectZoneServer");

	bool result = false;
	SESSION_USER_DATA userdata;
	GateService* service = NULL;
	ServiceConnect* serviceConnect = NULL;

	MMOLOG_ASSERT_EXIT(context != NULL);
	service = (GateService*)context;
	serviceConnect = &service->m_zoneServer;

	if (success) 
	{
		MMOLOG_ASSERT_EXIT(session != NULL);
		serviceConnect->session = session;
		serviceConnect->connectState = CONNECT_STATE_CONNECTED;
		serviceConnect->serviceType = ZONE_SERVER;
		serviceConnect->session->SetUserReq((void*)(GateService::_OnCloseServer), context);
		serviceConnect->session->SetNetPackHandle((void*)(service->GetServiceMessageDispatch()));
		LogInfoFmtPrint("[gate] connect zone server(id:%u, ip:%s:%d) success",
						serviceConnect->id,
						serviceConnect->remoteIp,
						serviceConnect->remotePort);

		userdata.v32 = serviceConnect->id;
		session->SetUserData(userdata);
		session->SetMark(ZONE_SERVER);

		service->_Register2Zone();
	}
	else 
	{
		LogErrFmtPrint("[gate] connect zone server(id:%u, ip:%s:%d) fail",
						serviceConnect->id,
						serviceConnect->remoteIp,
						serviceConnect->remotePort);
		serviceConnect->connectState = CONNECT_STATE_READY;
	}

	result = true;
Exit0:
	return result;
}

bool GateService::_OnAcceptClient(ISession* session, void* context)
{
	bool retCode = true;
	uint32_t clientId = 0; 
	PROFILE_SEGMENT("GateService::_OnAcceptClient");

	MMO_ASSERT(session);
	MMO_ASSERT(context);

	bool result = false;
	GateService* service = (GateService*)context;
	SESSION_USER_DATA userData;
	pair<unordered_map<uint32_t, ClientSession>::iterator, bool> pret;

	ClientSession cSession;
	cSession.pSession = session;
	cSession.countMsgPerMin = 0;

	if (!service->IsRuning()) 
	{
		const SESSION_USER_DATA& refUserData = session->GetUserData();
		LogErrFmtPrint("GateService::_OnAcceptClient close session(%p) user data(v32:%u v64:%llu ptr:%p)",
						session, refUserData.v32, refUserData.v64, refUserData.ptr);
		service->CloseSession(session);
		goto Exit0;
	}

	session->SetUserReq((void *)(GateService::_OnCloseClient), context);
	session->SetNetPackHandle((void *)(service->GetServiceMessageDispatch()));
	session->SetMark(CLIENT_MART);
	session->SetEncrypt(false);
	
	static uint32_t s_clientSessioinId = 1;
	clientId = ((s_clientSessioinId++) % CLINET_SESSIONID_MAX) + (CLINET_SESSIONID_MAX*(service->m_id-1));

	pret = service->m_clientSessionMap.insert(CLIENT_SESSION_MAP::value_type(clientId, cSession));
	MMOLOG_PROCESS_ERRLOG(pret.second);

	userData.v32 = clientId;
	userData.ptr = &(pret.first->second);

	session->SetUserData(userData);

	pret.first->second.clientId = clientId;
	pret.first->second.pSession = session;
	pret.first->second.timeStamp = ServerTime::UnixSec();

	LogInfoFmtPrint("[gate] Client %s connect!, clientId:%d, timeStamp:%lu", session->GetRemoteAddress().IPAndPort, clientId, pret.first->second.timeStamp);
	MMOLOG_ASSERT_EXIT(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::_OnCloseClient(ISession* session, void* context, CloseFlag flag)
{
	MMO_ASSERT(session);
	MMO_USE_ARGUMENT(context);
	if (session == NULL) 
	{
		return false;
	}
	GateService* service = (GateService*)context;
	uint64_t cid = 0;

	uint32_t sessionId = session->GetUserData().v32;
	ClientSession* pCsession = (ClientSession*)session->GetUserData().ptr;
	if (pCsession == nullptr)
		LogErrFmtPrint("_OnCloseClient cannt find clientSession, clientId:%d", sessionId);
	else
		cid = pCsession->cid;

	g_GetGateMgr()->ClientDisConnect(sessionId);
	service->m_clientSessionMap.erase(sessionId);
	session->SetUserData(SESSION_USER_DATA());

	LogInfoFmtPrint("[gate] client disconnect, clientId:%d, cid:%lu", sessionId, cid);
	return true;
}

bool GateService::SendDataToClient(uint32_t clientId, uint16_t cmd, ProtoBufBase* data)
{
	bool result = false;
	bool retCode = false;

	CLIENT_SESSION_MAP::iterator iter = m_clientSessionMap.find(clientId);
	CLIENT_SESSION_MAP::iterator iterEnd = m_clientSessionMap.end();
	if (iter == iterEnd)
	{
		LogErrFmtPrint("send data to client, cannt find sessionId in clientsessionMap sessionId:%d, cmd:%d", clientId, cmd);
		return false;
	}

	retCode = SendData(iter->second.pSession, EMODULE_ID_SERV_SYS, cmd, data);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToClient(uint32_t clientId, const char* data, uint32_t len)
{
	bool result = false;
	bool retCode = false;
	CLIENT_SESSION_MAP::iterator iter = m_clientSessionMap.find(clientId);
	CLIENT_SESSION_MAP::iterator iterEnd = m_clientSessionMap.end();

	if (iter == iterEnd)
	{
		LogErrFmtPrint("send data to client, cannt find sessionId in clientsessionMap sessionId:%d", clientId);
		return false;
	}

	retCode = SendData(iter->second.pSession, data, len);
	MMO_PROCESS_ERROR(retCode);

	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToAllClient(const char* data, uint32_t len)
{
	
	bool result = false;
	bool retCode = false;
	CLIENT_SESSION_MAP::iterator iter = m_clientSessionMap.begin();
	CLIENT_SESSION_MAP::iterator iterEnd = m_clientSessionMap.end();

	for (; iter != iterEnd; iter++)
	{
		retCode = SendData(iter->second.pSession, data, len);
		MMO_PROCESS_ERROR(retCode);
	}

	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToClientCmd(uint32_t clientId, uint16_t cmd)
{
	bool result = false;
	bool retCode = false;

	ClientSession *pCsession = GetClientSession(clientId);
	MMO_PROCESS_ERROR(pCsession != nullptr);
	MMO_PROCESS_ERROR(pCsession->pSession != nullptr);

	retCode = SendData(pCsession->pSession, cmd);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToZone(uint16_t cmd, ProtoBufBase* data)
{
	bool result = false;
	bool retCode = false;
	retCode = SendData(m_zoneServer.session, EMODULE_ID_SERV_SYS, cmd, data);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToCenter(uint16_t module, uint16_t cmd, ProtoBufBase* data)
{
	bool result = false;
	bool retCode = false;
	MMO_PROCESS_ERROR(m_pCenterSession != nullptr);
	retCode = SendData(m_pCenterSession, module, cmd, data);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToCenter(const char* data, uint32_t len)
{
	bool result = false;
	bool retCode = false;
	MMO_PROCESS_ERROR(m_pCenterSession != nullptr);
	retCode = SendData(m_pCenterSession, data, len);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

const char* GateService::RepackRemovePreDataToClient(RECV_PACKAGE& package, uint32_t preDataLen)
{
	short clientIdCount = *(short*)package.dataAfterHead;

	if (clientIdCount >= 0)
		memcpy(m_tmpbuf, package.dataAfterHead + sizeof(short), preDataLen);
	else
		return nullptr;

	NetPack* pPack =(NetPack*)(package.dataAfterHead  + preDataLen - sizeof(NetPack));
	pPack->Reset();
	pPack->SetModule(package.moduleId);
	pPack->SetCmd(package.cmd);
	pPack->SetLength(package.len - preDataLen);

	
	package.msg = (char*)pPack;
	package.len = package.len - preDataLen;

	if (clientIdCount == 0)
		clientIdCount = m_clientSessionMap.size();

	g_GetProfileLogMgr()->SendCmdRecord(package.cmd, pPack->GetLength(), clientIdCount);

	return m_tmpbuf;
}

const char* GateService::RepackToClient(RECV_PACKAGE& package, uint32_t preDataLen)
{
	short clientIdCount = *(short*)package.dataAfterHead;

	NetPack* pPack = (NetPack*)m_tmpbuf;
	pPack->Reset();
	pPack->SetModule(package.moduleId);
	pPack->SetCmd(package.cmd);
	pPack->SetLength(package.len - preDataLen);

	char* pContent = m_tmpbuf + sizeof(NetPack);
	if (clientIdCount >= 0)
		memcpy(pContent, package.dataAfterHead + preDataLen, package.sizeAfterHead - preDataLen);

	package.len = package.len - preDataLen;

	if (clientIdCount == 0)
		clientIdCount = m_clientSessionMap.size();

	g_GetProfileLogMgr()->SendCmdRecord(package.cmd, pPack->GetLength(), clientIdCount);

	return m_tmpbuf;
}

const char* GateService::ClientDataRepackToServer(RECV_PACKAGE& package, uint64_t Id)
{
	NetPack* pPack = (NetPack*)m_serializeBuf;
	pPack->Reset();
	pPack->SetModule(package.moduleId);
	pPack->SetCmd(package.cmd);

	uint32_t totallength = package.sizeAfterHead + sizeof(NetPack);
	totallength += sizeof(uint64_t);

	uint64_t* pUint = (uint64_t*)(m_serializeBuf + sizeof(NetPack));
	*pUint = Id;
	pPack->SetLength(totallength);

	char* pContent = m_serializeBuf + sizeof(NetPack)+sizeof(uint64_t);

	if (package.sizeAfterHead > 0)
		memcpy(pContent, package.dataAfterHead, package.sizeAfterHead);

	return m_serializeBuf;
}

bool GateService::SendDataToLogic(uint32_t logicId, const char* data, uint32_t len)
{
	bool result = false;
	bool retCode = false;

	SESSION_MAP::iterator iter = m_logicSessionMap.find(logicId);
	SESSION_MAP::iterator iterEnd = m_logicSessionMap.end();
	if (iter == iterEnd)
	{
		LogErrFmtPrint("send data to logic, cannt find sessionId in clientsessionMap sessionId:%d", logicId);
		return false;
	}

	retCode = SendData(iter->second, data, len);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToLogic(uint32_t logicId, uint16_t module, uint16_t cmd, ProtoBufBase* data)
{
	bool result = false;
	bool retCode = false;

	SESSION_MAP::iterator iter = m_logicSessionMap.find(logicId);
	SESSION_MAP::iterator iterEnd = m_logicSessionMap.end();
	if (iter == iterEnd)
	{
		LogErrFmtPrint("send data to logic, cannt find sessionId in clientsessionMap sessionId:%d", logicId);
		return false;
	}

	retCode = SendData(iter->second, module,cmd,data);
	MMO_PROCESS_ERROR(retCode);
	result = true;
Exit0:
	return result;
}

bool GateService::SendDataToAllLogic(const char* data, uint32_t len)
{
	bool result = false;
	bool retCode = false;

	SESSION_MAP::iterator iter	  = m_logicSessionMap.begin();
	SESSION_MAP::iterator iterEnd = m_logicSessionMap.end();
	for (; iter != iterEnd; iter++)
	{
		retCode = SendData(iter->second, data, len);
		MMO_PROCESS_ERROR(retCode);
	}

	result = true;
Exit0:
	return result;
}

void GateService::GateLeaveGame(uint32_t clientId, bool force /* = false */, LOGOUT_FLAG flag)
{
	if (force)
	{
		NotifyLogoutGame leave;
		leave.set_flag(flag);

		ClientSession* pCsession = GetClientSession(clientId);
		if (pCsession == nullptr)
		{
			LogErrFmtPrint("force leave game session cannt find, id:%d, maybe already disconnect", clientId);
			return;
		}
		SendData(pCsession->pSession, EMODULE_ID_SERV_SYS, CENTER_TO_CLIENT_LOGINOUT, &leave);
		LogInfoFmtPrint("force leave game clientId:%d, cid:%lu", pCsession->clientId, pCsession->cid);
		CloseSession(pCsession->pSession);
	}
	else
	{
		SendDataToClientCmd(clientId, CENTER_TO_CLIENT_LOGINOUT);
	}
	m_clientSessionMap.erase(clientId);
}

ClientSession* GateService::GetClientSession(uint32_t clientId)
{
	CLIENT_SESSION_MAP::iterator  iter;
	CLIENT_SESSION_MAP::iterator iterEnd = m_clientSessionMap.end();
	iter = m_clientSessionMap.find(clientId);
	if (iter == iterEnd)
		return nullptr;
	return &iter->second;
}

uint32_t GateService::GetPlayerCount(bool syn /* = false */)
{
	return (uint32_t)m_clientSessionMap.size();
}

bool GateService::TrueClientMessage(RECV_PACKAGE& package)
{
    bool result = false;
	uint32_t diffTime = 0;
	uint32_t packageNum = 0;
	uint32_t clientId = 0;
	uint32_t packgeErrorPingNum = 0;

	uint64_t endTimeStamp = ServerTime::UnixSec();
	uint64_t startTimeStamp = 0;
	ClientSession * pCsession = nullptr;

	clientId = package.session->GetUserData().v32;
	pCsession = (ClientSession*) package.session->GetUserData().ptr;
	startTimeStamp = pCsession->timeStamp;

	MMOLOG_PROCESS_ERROR(pCsession != nullptr);

	diffTime = (uint32_t)(endTimeStamp - startTimeStamp);

	if (package.cmd == CLIENT_TO_LOGIC_PING)
	{
		PingLogicServer rsp;
		if (!rsp.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
		{
			LogErrFmtPrint("[gate] GateService::TrueClientMessage  ping prase failed...");
			return false;
		}
		
		int64_t tmpTime = (int64_t)rsp.clienttick() - (int64_t)Time::Now().UnixMSec();
		if (tmpTime >= 2000)
		{
			pCsession->conutMsgPing++;
		}
  //   	PingRsp crsp;
		//crsp.set_currentmstime(Time::Now().UnixMSec());
		////LogDebugFmtPrint("test clienttime=%lu,servertime=%lu,interval=%ld", rsp.clienttick(), endTimeStamp, tmpTime);
		//return g_GetGateService()->SendDataToClient(package.session->GetUserData().v32, SERVER_TO_CLIENT_PING, &rsp);
	}

	if (pCsession->countMsgPerMin > GATE_PACKAGE_CHECK_MIN || diffTime >= 60)
	{
		packageNum = GATE_PACKAGE_PER_SEC * diffTime;
		packgeErrorPingNum = (GATE_PACKAGE_CMD_PING_NUM *1.0*diffTime) / 60;
		if (pCsession->countMsgPerMin > packageNum || pCsession->conutMsgPing>=packgeErrorPingNum)
		{
			LogErrFmtPrint("recv client packageCount:%d > %d in one mintue between %lu---%lu, close session, clientId:%d, cid:%lu,errorping=%d > %d", pCsession->countMsgPerMin, GATE_PACKAGE_CHECK_MIN, startTimeStamp, endTimeStamp, clientId, pCsession->cid, pCsession->conutMsgPing, packgeErrorPingNum);
			goto Exit0;
		}
		pCsession->countMsgPerMin = 0;
		pCsession->conutMsgPing = 0;
		pCsession->timeStamp = endTimeStamp;
	}
	g_GetGateMgr()->ClientTransDataToLogicOrCenter(package.cmd, package); 
	pCsession->countMsgPerMin++;



    result = true;
Exit0:
	if (!result)  //直接发送被T消息给客户端
	{
		NotifyLogoutGame leave;
		leave.set_flag(LOGOUT_FLAG_CHEAR_KICK);
		SendData(package.session, EMODULE_ID_SERV_SYS, CENTER_TO_CLIENT_LOGINOUT, &leave);
		CloseSession(package.session);
		m_clientSessionMap.erase(package.session->GetUserData().v32);
	}
	return true;
}

bool GateService::_Register2Zone()
{
    bool result = false;
    bool retCode = false;
	RegServerInfo srvInfo;

	srvInfo.set_id(m_id);
	srvInfo.set_clientip(m_clientListenIp);
	srvInfo.set_clientport(m_clientPort);

	retCode = SendData(m_zoneServer.session, EMODULE_ID_SERV_SYS, GATE_REGISTER_ZONE_REQ, &srvInfo);
	MMOLOG_PROCESS_ERROR(retCode);

    result = true;
Exit0:
	return result;
}

uint32_t GateService::ProfileOnlineNum()
{
	GateService* gateSerivce = g_GetGateService();
	if (nullptr == gateSerivce || gateSerivce->m_lstOnline.empty())
		return 0;

	uint32_t num = 0;
	list<uint32_t>::iterator iter = gateSerivce->m_lstOnline.begin();
	uint32_t sumOnline = 0;
	for (; iter != gateSerivce->m_lstOnline.end(); iter++)
	{
		sumOnline += *iter;
	}
	num = sumOnline / gateSerivce->m_lstOnline.size();
	gateSerivce->m_lstOnline.clear();

	return num;
}